#include "rules.h"

void Rules::assertz (pNode &rule) {
  Node &final = *rule.final ();

  // Ignore empty atoms ($)
  if(final.type () == Atom::ID && static_cast<Atom&> (final).name == "")
    return;

  lock.lockWrite ();
  pNode replicated = final.replicate ();
  Prototype proto = Prototype::getFromRule (*replicated);
  snippets[proto].invalidate (); // Recompiles byte-code in next run

  rules.push_back (replicated);
  indexByPrototype[proto].push_back (replicated);

  updateCounts ();
  lock.unlockWrite ();
}

void Rules::retract (Node *rule) {
  lock.lockWrite ();
  Prototype proto = Prototype::getFromRule (*rule);
  snippets[proto].invalidate (); // Recompiles byte-code in next run

  // Erases from index first
  //  Index::iterator iter = indexByPrototype.lower_bound (proto);
  //  Index::iterator end = indexByPrototype.upper_bound (proto);
  //  for(; iter != end; iter++)
  //    if((*iter).second == rule) {
  //      indexByPrototype.erase (iter);
  //      break;
  //    }
  std::vector<Node*>& list = indexByPrototype[proto];
  std::vector<Node*>::iterator iter = list.begin (), end = list.end ();
  for(; iter != end; iter++)
    if(*iter == rule) {
      list.erase (iter);
      break;
    }

  // Traverses the all rules list and erase.
  // This is inefficient but retract is not often called anyway
  for(std::vector<pNode>::iterator p = rules.begin (); p < rules.end (); p++)
    if((*p).node == rule)
      rules.erase (p); // Erases from all clauses list

  updateCounts ();
  lock.unlockWrite ();
}

void Rules::buildIndex () {
  indexByPrototype.clear ();
  for(unsigned int index = 0; index < rules.size (); index++)
    indexByPrototype[Prototype::get (*rules[index])].push_back (rules[index]);
}

Snippet &Rules::findSnippet (Prototype &proto) {
  lock.lockRead ();

  Snippet *ret = 0;
  Snippets::iterator iter = snippets.find (proto);
  if(iter != snippets.end ()) {
    ret = &(*iter).second;
    if(!ret->valid)
      ret = 0;
  }

  lock.unlockRead ();
  return *ret;
}

Snippet &Rules::putSnippet (const Prototype &proto, const Snippet &snippet) {
  lock.lockWrite ();
  Snippet &ret = snippets[proto] = snippet;
  lock.unlockWrite ();
  return ret;
}

// Iterator for total traversal in a rules database
class AllRulesSearcherIterator : public RulesIterator {
public:
  AllRulesSearcherIterator (std::vector<pNode> &l) :
    nodes (l), index (0) {
  }

  Node *operator * () {
    return nodes[index];
  }

  void next () {
    index++;
  }

  bool valid () {
    return index < nodes.size ();
  }

  std::vector<pNode> &nodes;
  unsigned int index;
};

RulesIterator *Rules::createIteratorForAll () {
  return new AllRulesSearcherIterator (rules);
}

// Iterator only traverse rules with specified clause names
class PrototypeSearcherIterator : public RulesIterator {
public:
  PrototypeSearcherIterator (Rules::Index &ci, const Prototype &key) :
    list(ci[key]), iterator(list.begin ()) {}

  Node *operator * () {
    return *iterator;
  }

  void next () {
    iterator++;
  }

  bool valid () {
    return iterator < list.end ();
  }

  std::vector<Node*>& list;
  std::vector<Node*>::iterator iterator;
};

RulesIterator *Rules::createIteratorForPrototype (const Prototype &proto) {
  return new PrototypeSearcherIterator (indexByPrototype, proto);
}
